﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FunctionalLayer
{
    /// <summary>
    /// Contains all the lap data
    /// </summary>
    public class Lap
    {
        #region Fields
        /// <summary>
        /// List of current lap times
        /// </summary>
        private TimeSpan[] _sectionTimes;

        private TimeSpan[] _lapTimes;

        /// <summary>
        /// Current lap time
        /// </summary>
        private Stopwatch _curSectionTime;

        /// <summary>
        /// Total elapsed time 
        /// </summary>
        private Stopwatch _totalElapsedTime;

        private Stopwatch _curLapTime;

        /// <summary>
        /// Property of StopWatch _curLapTime to get the current elapsed time
        /// </summary>
        public Stopwatch CurLapTime
        {
            get { return _curSectionTime; }
        }

        /// <summary>
        /// Current section number
        /// </summary>
        private int _currentSectionNumber;
        private int _currentLapNumber;

        public int CurrentSectionNumber
        {
            get { return _currentSectionNumber; }
        }
        #endregion

        /// <summary>
        /// Constructor
        /// </summary>
        public Lap()
        { 
        }

        /// <summary>
        /// Start new Lap
        /// </summary>
        public void Start()
        {
            _curSectionTime = new Stopwatch();
            _curLapTime = new Stopwatch();
            _sectionTimes = new TimeSpan[ConfigSingleton.Settings.SectionsPerLap];
            _lapTimes = new TimeSpan[ConfigSingleton.Settings.Laps];
            _totalElapsedTime = new Stopwatch();
            _currentSectionNumber = 0;
            _currentLapNumber = 1;
            _curLapTime.Start();
            _totalElapsedTime.Start();
            _curSectionTime.Start();
        }

        /// <summary>
        /// Stop race
        /// </summary>
        public void Stop()
        {
            _totalElapsedTime.Stop();
            _curSectionTime.Stop();
        }

        /// <summary>
        /// Start new lap time
        /// </summary>
        public void NewSection()
        {
            //http://stackoverflow.com/questions/7336932/how-to-convert-milliseconds-to-date-format-in-c
            var sectionTime = TimeSpan.FromMilliseconds(_curSectionTime.ElapsedMilliseconds);
            //add lap time to list
            _sectionTimes[_currentSectionNumber % ConfigSingleton.Settings.SectionsPerLap] = sectionTime;

            _curSectionTime.Reset();
            _curSectionTime.Start();
            _currentSectionNumber++;

            if (_currentSectionNumber == ConfigSingleton.Settings.SectionsPerLap * _currentLapNumber)
            {
                var lapTime = TimeSpan.FromMilliseconds(_curLapTime.ElapsedMilliseconds);
                _lapTimes[_currentLapNumber -1] = lapTime;
                _curLapTime.Reset();
                _curLapTime.Start();
                _currentLapNumber++;

                if (_currentLapNumber > ConfigSingleton.Settings.Laps)
                {
                    _currentLapNumber = ConfigSingleton.Settings.Laps;
                }
            }
        }

        /// <summary>
        /// Get Total elapsed time
        /// </summary>
        /// <returns>Timespan total time</returns>
        public TimeSpan GetTotalTime()
        {
            //http://stackoverflow.com/questions/7336932/how-to-convert-milliseconds-to-date-format-in-c
            var time = TimeSpan.FromMilliseconds(_totalElapsedTime.ElapsedMilliseconds);
            return time;
        }
        /// <summary>
        /// Get time that is left
        /// </summary>
        /// <returns>Maximum time minus total time (time that is left)</returns>
        public TimeSpan GetTimeLeft(TimeSpan totalTime, TimeSpan maximumTime)
        {
            var time = new TimeSpan(maximumTime.Hours - totalTime.Hours, maximumTime.Minutes - totalTime.Minutes, maximumTime.Seconds - totalTime.Seconds);
            if (time.Seconds < 1)
                return new TimeSpan(0, 0, 0);
            return time;
        }

        /// <summary>
        /// Get current section time
        /// </summary>
        /// <returns>Timespan current time</returns>
        public TimeSpan GetCurrentTime()
        {
            //http://stackoverflow.com/questions/7336932/how-to-convert-milliseconds-to-date-format-in-c
            var time = TimeSpan.FromMilliseconds(_curLapTime.ElapsedMilliseconds);
            return time;
        }

        /// <summary>
        /// When a new lap is entered, call this method
        /// </summary>
        /// <returns>The current lap number</returns>
        public int NewLap()
        {
            for (int i = 0; i < ConfigSingleton.Settings.SectionsPerLap; i++)
            {
                NewSection();
            }

            return _currentLapNumber;
        }

        /// <summary>
        /// Get previous/ last time
        /// </summary>
        /// <returns>Timespan previous time</returns>
        public TimeSpan GetPreviousSectionTime(int section)
        {
            if (_sectionTimes.Length > 1)
            {
                return _sectionTimes[section % ConfigSingleton.Settings.SectionsPerLap];
            }
            return new TimeSpan(-1, -1, -1);
        }

        /// <summary>
        /// Returns the time of the previous lap
        /// </summary>
        /// <returns>The time it took to drive the previous lap</returns>
        public TimeSpan GetPreviousLapTime()
        {
            if (_currentLapNumber > 1)
            {
                return _lapTimes[_currentLapNumber - 2];
            }
            return new TimeSpan(0, 0, 0);
        }

        ///TODO : calculate which lap and time left for the lap
        public TimeSpan GetAdviceTime(TimeSpan timeLeft)
        {
            /*
            int currentLap = (int)(distance % ConfigSingleton.Settings.LapDistance);
            int lapsleft = ConfigSingleton.Settings.Laps - currentLap;

            int secondsLeft = timeLeft.Minutes * 60 + timeLeft.Seconds;
            int currentLapSeconds = currentTime.Minutes * 60 + timeLeft.Seconds;
            int advicedTimePerLap = (secondsLeft + currentLapSeconds) / (lapsleft + 1);
            int adviceSeconds = advicedTimePerLap - currentLapSeconds;
            return new TimeSpan(0, adviceSeconds / 60, adviceSeconds % 60);
             */

            int advise = Convert.ToInt32(timeLeft.TotalSeconds / (ConfigSingleton.Settings.Laps - (_currentLapNumber -1)));
            TimeSpan time = TimeSpan.FromSeconds(advise);
            return time;
          
            //int perSection = Convert.ToInt32(totalSeconds / sectionsLeft);
            //return new TimeSpan(0, perSection / 60, perSection % 60);
        }
    }
}